use serde_derive::Deserialize;
use std::collections::HashMap;
use std::str::FromStr;

use serde::Serialize;
use serde_json::Value; 

use crate::mylib::util_date;

use super::my_cache;
use super::my_err::MyErr;

// 百运安 接口
#[derive(Deserialize)]
pub struct Bya {
    pub domain: String,
    pub username: String,
    pub password: String,
}

// 车辆行驶里程接口返回的数据
#[derive(serde::Serialize)]
#[warn(dead_code)]
pub struct CarInfoBean {
    pub vehicle_id: String,                  // 车辆ID
    pub vehicle_plate: String,               // 车牌号
    pub device_no: String,                   // 设备号。
    pub drive_lisence_check_day: String,    // 年检日期
    pub drive_lisence_no: String,            // 行驶证号
    pub drive_lisence_register_day: String, // 注册日期
    pub drive_lisence_send_day: String,     // 发证日期
    pub engine_number: String,               // 发动机编号
    pub label_model_id: String,              // 厂牌型号ID
    pub label_model_name: String,            // 厂牌型号
    pub totle_seat: i32,                     // 座位数
    pub use_seat: i32,                       // 客座数
}

impl Bya { 

    /// 根据车牌号获取车辆详情
    /// vehicle_plate：车牌号  
    #[allow(dead_code)]
    pub async fn get_car_info(&self, vehicle_plate: &str) -> Result<CarInfoBean, MyErr> {
        let session = self.get_session().await?;

        let mut form_data = HashMap::new();
        form_data.insert("session", session);
        form_data.insert("vehiclePlate", vehicle_plate.to_string());

        let url = format!("https://{}/source/sourceapi/single/vehicle", self.domain);
        let rs = post_from_data_to_url(&url, &form_data).await;
        log::info!("\n\n\n\n\n\n rs:{:?} \n\n\n\n\n\n\n\n", rs);
        match rs {
            Ok(res) => {
                let code = res.get("code").and_then(Value::as_i64).unwrap_or(-1);
                if code == 0 {
                    if let Some(data) = res.get("data") {
                        let vehicle_id= data.get("vehicleId").and_then(Value::as_str).unwrap_or_default().to_string();
                        let vehicle_plate= data.get("vehiclePlate").and_then(Value::as_str).unwrap_or_default().to_string();
                        let device_no= data.get("deviceNo").and_then(Value::as_str).unwrap_or_default().to_string();
                        let drive_lisence_check_time= data.get("driveLisenceCheckTime").and_then(Value::as_str).unwrap_or_default();
                        let drive_lisence_no= data.get("driveLisenceNo").and_then(Value::as_str).unwrap_or_default().to_string();
                        let drive_lisence_register_time= data.get("driveLisenceRegisterTime").and_then(Value::as_str).unwrap_or_default();
                        let drive_lisence_send_time= data.get("driveLisenceSendTime").and_then(Value::as_str).unwrap_or_default();
                        let engine_number= data.get("engineNumber").and_then(Value::as_str).unwrap_or_default().to_string();
                        let label_model_id= data.get("labelModelId").and_then(Value::as_str).unwrap_or_default().to_string();
                        let label_model_name= data.get("labelModelName").and_then(Value::as_str).unwrap_or_default().to_string();
                        let totle_seat= data.get("totleSeat").and_then(Value::as_i64).unwrap_or_default() as i32;
                        let use_seat= data.get("useSeat").and_then(Value::as_i64).unwrap_or_default() as i32;

                        let drive_lisence_check_time_number = i64::from_str(drive_lisence_check_time).unwrap_or_default();
                        let drive_lisence_register_time_number = i64::from_str(drive_lisence_register_time).unwrap_or_default();
                        let drive_lisence_send_time_number = i64::from_str(drive_lisence_send_time).unwrap_or_default();

                        let drive_lisence_check_day = util_date::milliseconds_to_str(drive_lisence_check_time_number, "%Y-%m-%d");
                        let drive_lisence_register_day = util_date::milliseconds_to_str(drive_lisence_register_time_number, "%Y-%m-%d");
                        let drive_lisence_send_day = util_date::milliseconds_to_str(drive_lisence_send_time_number, "%Y-%m-%d");

                        Ok(CarInfoBean{
                            vehicle_id,
                            vehicle_plate,
                            device_no,
                            drive_lisence_check_day,
                            drive_lisence_no,
                            drive_lisence_register_day,
                            drive_lisence_send_day,
                            engine_number,
                            label_model_id,
                            label_model_name,
                            totle_seat,
                            use_seat,
                        })
                    } else {
                        Err(MyErr::Msg(format!("缺少车辆详情数据！url:{} ", url)))
                    }
                } else {
                    Err(MyErr::Msg(format!("获取车辆信息失败！错误码：{} url:{} ", code, url)))
                }
            }
            Err(e) => Err(MyErr::Msg(format!("连接url地址失败！错误：{:?} url:{} ", e, url))),
        }
    }

    /// 获取授权方令牌（authorization_access_token 即公众号的 access_token）
    async fn get_session(&self) -> Result<String, MyErr> {
        if let Some(s) = my_cache::get("BYA_LOGIN_JSESSION") {
            // 如果在缓存中已经存在 jsession 则直接返回
            log::info!("缓存中已经存在 jsession ，直接获取并返回: {}", s);
            Ok(s)
        } else {
            // 如果缓存中没有，则登录接口获取

            let mut form_data = HashMap::new();
            form_data.insert("username", self.username.clone());
            form_data.insert("password", self.password.clone());

            let url = format!("https://{}/source/sourceapi/get/assesstoken", self.domain);
            let rs = post_from_data_to_url(&url, &form_data).await;
            match rs {
                Ok(res) => {
                    let code = res.get("code").and_then(Value::as_i64).unwrap_or(-1);
                    if code == 0 {
                        let session = res.get("data").and_then(Value::as_str).unwrap_or_default();
                        let expires_in = 7 * 60 * 60; // 单位（秒），7小时
                        my_cache::set("BYA_LOGIN_JSESSION", session.to_string(), expires_in);

                        Ok(session.to_string())
                    } else {
                        Err(MyErr::Msg(format!("登录失败！错误码：{} url:{} ", code, url)))
                    }
                }
                Err(e) => Err(MyErr::Msg(format!("连接url地址失败！错误：{:?} url:{} ", e, url))),
            }
        }
    }
}

async fn post_from_data_to_url<T: Serialize + std::fmt::Debug + ?Sized>(url: &str, form_data: &T) -> Result<Value, MyErr> {
    log::info!("\n\n\n url:{} data:{:?} \n\n\n\n", url, form_data);

    let client = reqwest::Client::new();
    let rs = client.post(url).form(form_data).send().await;
    match rs {
        Ok(res) => match res.json::<serde_json::Value>().await {
            Ok(v) => Ok(v),
            Err(e) => {
                log::error!("读取URL数据失败！错误：{:?} url:{} post_form_data:{:?}", e, url, form_data);
                Err(MyErr::Msg("网络异常！".to_string()))
            }
        },
        Err(e) => {
            log::error!("连接url地址失败！错误：{:?} url:{} post_form_data:{:?}", e, url, form_data);
            Err(MyErr::Msg("网络异常！".to_string()))
        }
    }
}
